package service

import (
	"bufio"
	"gitee.com/molonglove/goboot/gorm"
	"helper-api/app/models/entity"
	"helper-api/app/models/request"
	"helper-api/app/models/response"
	"helper-api/core"
	"helper-api/utils"
	"io"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
)

var Software = new(SoftwareService)

type SoftwareService struct{}

// Download 下载软件
func (s *SoftwareService) Download(id, userId int64) *response.BusinessError {
	var (
		err      error
		software entity.Software
	)
	if err = core.DB.Model(&entity.Software{}).Where("id = ? and can_view = 1", id).First(&software).Error; err != nil {
		core.Log.Error("软件不存在")
		return response.NewBusinessError(response.DataNotExist)
	}
	// 开启协程异步下载安装包
	go s.download(userId, software.Title, software.Version, software.Url)
	return nil
}

func (s *SoftwareService) download(userId int64, title, version, url string) {
	var (
		target []string
		name   string
		paths  string
		err    error
		file   *os.File
		resp   *http.Response
		writer *bufio.Writer
	)
	defer func() {
		resp.Body.Close()
		file.Close()
	}()
	target = strings.Split(url, "/")
	name = target[len(target)-1]
	core.Log.Info("开始下载[%s]:[v%s]的安装包 => %s", title, version, url)
	// https://www.twle.cn/t/384
	if resp, err = http.Get(url); err != nil {
		core.Log.Error("下载资源失败 => %s", err.Error())
		core.WS.SendMsg(userId, response.NewWebsocketResponse("software", "下载资源失败", "error").BuildMessage())
		return
	}
	paths = path.Join(core.MockConfig.Server.Storage, title, version)
	if err = utils.CreateDir(paths); err != nil {
		core.Log.Error("下载资源失败 => %s", err.Error())
		core.WS.SendMsg(userId, response.NewWebsocketResponse("software", "下载资源失败", "error").BuildMessage())
		return
	}
	if file, err = os.Create(path.Join(paths, name)); err != nil {
		core.Log.Error("下载资源失败 => %s", err.Error())
		core.WS.SendMsg(userId, response.NewWebsocketResponse("software", "下载资源失败", "error").BuildMessage())
		return
	}
	writer = bufio.NewWriter(file)
	if _, err = io.Copy(writer, resp.Body); err != nil {
		core.Log.Error("下载资源失败 => %s", err.Error())
		core.WS.SendMsg(userId, response.NewWebsocketResponse("software", "下载资源失败", "error").BuildMessage())
		return
	}
	core.WS.SendMsg(userId, response.NewWebsocketResponse("software", "下载安装包成功", "success").BuildMessage())
	core.Log.Info("下载[%s]:[v%s]的安装包完成 => %s", title, version, url)
}

// PageSearch 分页查询
func (s *SoftwareService) PageSearch(request *request.SoftwarePageRequest) (*response.PageData, *response.BusinessError) {
	var (
		err     error
		err1    *response.BusinessError
		tx      *gorm.DB
		total   int64
		records []entity.Software
		result  *response.PageData
	)
	tx = core.DB.Model(&entity.Software{}).Where("can_view = 1")
	if request.Type != "" {
		tx.Where("type_name = ?", request.Type)
	}
	if err = tx.Count(&total).Error; err != nil {
		core.Log.Error("统计SQL执行错误 => %s", err.Error())
		return result, response.NewBusinessError(response.SqlExecuteError)
	}
	if total != 0 {
		tx = core.DB.Model(&entity.Software{})
		if request.Type != "" {
			tx.Where("type_name = ?", request.Type)
		}
		if err = tx.Where("can_view = 1").Order("create_time").Offset(request.Offset()).Limit(request.Size).Find(&records).Error; err != nil {
			core.Log.Error("SQL执行错误 => %s", err.Error())
			return result, response.NewBusinessError(response.SqlExecuteError)
		}
	}
	result = response.NewPageData(request.Page, request.Size, total, records)
	return result, err1
}

// Types 获取软件的类型
func (s *SoftwareService) Types() ([]string, *response.BusinessError) {
	result := make([]string, 0)
	if err := core.DB.Model(&entity.Software{}).
		Select("type_name").
		Where("can_view = 1").
		Group("type_name").
		Scan(&result).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return result, response.NewBusinessError(response.SqlExecuteError)
	}
	return result, nil
}

// Create 创建
func (s *SoftwareService) Create(param *request.SoftwareCreateRequest) (*entity.Software, *response.BusinessError) {
	var (
		result *entity.Software
		total  int64
		err    error
	)
	if err = core.DB.Model(&entity.Software{}).
		Where("can_view = 1 and type_name = ? and title = ? and version = ? and os = ?", param.TypeName, param.Title, param.Version, param.Os).
		Count(&total).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if total > 0 {
		core.Log.Error("查询到相同的数据 => %d条", total)
		return nil, response.NewBusinessError(response.ExistSameData)
	}
	result = &entity.Software{
		TypeName:   param.TypeName,
		Title:      param.Title,
		Url:        param.Url,
		Version:    param.Version,
		CreateId:   param.UserId,
		CreateTime: time.Now(),
		CanView:    1,
	}
	if err = core.DB.Model(&entity.Software{}).Create(result).Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SoftwareCreateError)
	}
	return result, nil
}

// Update 更新
func (s *SoftwareService) Update(param *request.SoftwareUpdateRequest) (*entity.Software, *response.BusinessError) {
	var (
		isUpdate bool
		result   entity.Software
		err      error
	)
	if err = core.DB.Model(&entity.Software{}).Where("id = ? and can_view = 1", param.Id).First(&result).Error; err != nil {
		core.Log.Error("执行SQL查询错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if result.Title != param.Title {
		result.Title, isUpdate = param.Title, true
	}
	if result.TypeName != param.TypeName {
		result.TypeName, isUpdate = param.TypeName, true
	}
	if result.Version != param.Version {
		result.Version, isUpdate = param.Version, true
	}
	if result.Url != param.Url {
		result.Url, isUpdate = param.Url, true
	}
	if isUpdate {
		result.UpdateId = param.UserId
		result.UpdateTime = time.Now()
		if err = core.DB.Save(&result).Error; err != nil {
			core.Log.Error("执行SQL更新错误 => %s", err.Error())
			return nil, response.NewBusinessError(response.SqlExecuteError)
		}
		return &result, nil
	}
	return nil, response.NewBusinessError(response.DataNotNeedUpdate)
}

// Delete 删除
func (s *SoftwareService) Delete(ids []int64, userId int64) *response.BusinessError {
	if err := core.DB.Model(&entity.Software{}).
		Where("id in ?", ids).
		Updates(map[string]interface{}{"update_id": userId, "update_time": time.Now(), "can_view": 0}).
		Error; err != nil {
		core.Log.Error("执行SQL删除错误 => %s", err.Error())
		return response.NewBusinessError(response.SqlExecuteError)
	}
	return nil
}
